import axios from 'axios'
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
import { tool } from '@/utils/tool'
import router from '@/router'
import { useSysGlobalStore } from '@/stores/global.ts'
import { useAuthStore } from '@/stores/modules/auth.ts'
import defaultConfig from '@/config'
import { myConfig } from '@/config/myConfig.ts'
import feedback from '@/utils/feedback.ts'
import { RequestCodeEnum } from '@/enum/requestEnum.ts'

// 防止多个API同时401时疯狂弹窗的变量
let MessageBox_401_show = false

// 初始化Axios配置
axios.defaults.withCredentials = false
axios.defaults.baseURL = defaultConfig.API_URL
axios.defaults.timeout = defaultConfig.TIMEOUT

// HTTP请求拦截器
axios.interceptors.request.use(
    async (config) => {
        // 默认语言
        const sysGlobalStore = useSysGlobalStore()
        const sysLang = sysGlobalStore.sysLang
        if (sysLang) {
            config.headers['cb-lang'] = sysLang
        }

        // 授权令牌
        const authStore = useAuthStore()
        let accessToken: string | null = authStore.token.accessToken

        // 如果Token即将过期，尝试刷新
        if (accessToken && authStore.needRefresh(accessToken)) {
            accessToken = await authStore.refreshToken()
        }

        if (accessToken) {
            config.headers[defaultConfig.TOKEN_NAME] = `${defaultConfig.TOKEN_PREFIX}${accessToken}`
        }

        // 请求缓存
        if (!defaultConfig.REQUEST_CACHE && config.method === 'get') {
            config.params = config.params || {}
        }

        // 合并请求头
        Object.assign(config.headers, defaultConfig.HEADERS)

        return config
    },
    (error) => {
        return Promise.reject(error)
    }
)

// HTTP响应拦截器
interface ResponseData {
    status: string | number

    data: any
    message: string
}

axios.interceptors.response.use(
    (response: AxiosResponse) => {
        const hasCodeDataMessage = (obj: ResponseData) => {
            return 'status' in obj && 'data' in obj && 'message' in obj
        }

        if (hasCodeDataMessage(response.data)) {
            const { status, message } = response.data
            const config = response.config as any
            switch (status) {
                case RequestCodeEnum.OK:
                    if (config.method == 'post') feedback.success(message)

                    return response.data
                case RequestCodeEnum.FAIL:
                    feedback.error(message)

                    // 检查是否需要await
                    if (config.await) {
                        feedback.closeLoading()
                        return false
                    } else {
                        feedback.closeLoading()
                        return Promise.reject(message)
                    }
                default:
                    return response.data
            }
        } else {
            return Promise.reject()
        }
    },
    (error) => {
        if (error.response) {
            handleErrorStatus(error)
        } else {
            feedback.error('请求服务器无响应')
        }

        return Promise.reject(error)
    }
)

// 请求方法
export const http = {
    get(url: string, params: object = {}, config: AxiosRequestConfig = {}): Promise<any> {
        return sendRequest('get', url, encryptData(params), config)
    },

    post(url: string, data: object = {}, config: AxiosRequestConfig = {}): Promise<any> {
        return sendRequest('post', url, encryptData(data), config)
    }
}

// 通用请求发送函数
async function sendRequest(
    method: 'get' | 'post',
    url: string,
    payload: object,
    config: AxiosRequestConfig = {}
): Promise<any> {
    return new Promise((resolve, reject) => {
        axios({
            method,
            url,
            params: method === 'get' ? payload : undefined,
            data: method === 'post' ? payload : undefined,
            ...config
        })
            .then((res) => {
                resolve(decryptResponse(res))
            })
            .catch((err) => {
                reject(err)
            })
    })
}

// 请求参数加密
function encryptData(data: object = {}): object {
    if (Object.keys(data).length > 0 && myConfig.MY_AES_ACTIVE) {
        const timestamp = String(parseInt(String(Date.now() / 1000)))
        const encryptedData = tool.crypto.AES.encrypt(
            JSON.stringify(data),
            `${timestamp}${myConfig.MY_AES_KEY}`,
            {
                iv: myConfig.MY_AES_IV,
                mode: 'CBC'
            }
        )

        return {
            t: timestamp,
            k: encryptedData
        }
    }
    return data
}

// 响应数据解密
function decryptResponse(response: AxiosResponse) {
    if (myConfig.MY_AES_ACTIVE && response.data && response.data.data && response.data.data.k) {
        const decryptedData = tool.crypto.AES.decrypt(
            response.data.data.k,
            `${response.data.data.t}${myConfig.MY_AES_KEY}`,
            { iv: myConfig.MY_AES_IV, mode: 'CBC' }
        )
        response.data.data = {
            ...(response.data.data as any), // 保留其他可能的属性
            ...JSON.parse(decryptedData)
        }
    }

    return response.data
}

// 失败状态拦截
async function handleErrorStatus(error: any) {
    const { status, data } = error.response
    switch (status) {
        case 404:
            feedback.error('status:404，正在请求不存在的服务器记录！')
            break
        case 500:
            feedback.error(data.message || 'status:500，服务器发生错误！')
            break
        case 401:
            // 如果是401错误，且未进行过重试
            const originalRequest = error.config
            if (!originalRequest._retry) {
                originalRequest._retry = true

                // 尝试刷新Token
                const authStore = useAuthStore()
                const newToken = await authStore.refreshToken()
                if (newToken) {
                    // 使用新Token重新请求
                    originalRequest.headers[defaultConfig.TOKEN_NAME] =
                        `${defaultConfig.TOKEN_PREFIX}${newToken}`

                    return axios(originalRequest)
                }
            }

            if (!MessageBox_401_show) {
                MessageBox_401_show = true
                await feedback.confirm(
                    '当前用户已被登出或无权限访问当前资源，请尝试重新登录后再操作。',
                    '无权限访问',
                    {
                        type: 'error',
                        closeOnClickModal: false,
                        center: true,
                        showCancelButton: false,
                        showClose: false,
                        confirmButtonText: '重新登录',
                        beforeClose: (action, instance, done) => {
                            MessageBox_401_show = false
                            done()
                        }
                    }
                )

                useAuthStore().$reset()
                router
                    .replace({ path: '/login', replace: true })
                    .then((r) => console.log('r', r))
                    .catch((err) => console.log('err', err))
            }
            break
        default:
            feedback.error(error.message || `code:${status}，未知错误！`)
    }
}
